#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <functional>
#include "Task.hpp"
#include "Channel.hpp"

// typedef std::function<void()> work_t;
using work_t = std::function<void()>; // 定义函数对象类型
// 包装器 --- 保存任何可调用的对象

enum
{
    OK = 0,
    UsageError,
    PipeError,
    ForkError
};

class ProcessPool
{
public:
    ProcessPool(int n, work_t w) 
    : processnum(n), work(w)
    {}
    // channels: 输出型参数
    // work_t work : 回调  让子进程执行其他任务
    int InitProcessPool()
    {
        // 2. 创建指定个数个进程
        for (int i = 0; i < processnum; i++)
        {
            // 1. 先有管道
            int pipefd[2] = {0};
            int n = pipe(pipefd);
            if (n < 0)
                return PipeError;

            // 2. 创建进程
            pid_t id = fork();
            if (id < 0)
                return ForkError;

            // 3. 建立信道
            if (id == 0) // 子进程
            {
                ::close(pipefd[1]); // read
                dup2(pipefd[0], 0); // 重定向到pipefd[0]读端上，让子进程的读取在标准输入中
                Worker();           // 子进程进行读取操作
                ::exit(0);
            }
            // 父进程执行
            ::close(pipefd[0]); // wirte
            channels.emplace_back(pipefd[1], id);
            // Channel ch(pipefd[1], id);// 向子进程写入
            // channels.push_back(ch);// 循环num次，就维护了num个管道
        }
        return OK;
    }

    void DispatchTask()
    {
        int who = 0;
        // 2. 派发任务
        int num = 20;
        while (num--)
        {
            // a. 选择一个任务，整数
            int task = tm.SelectTask();
            // b. 选择一个子进程channel
            Channel &curr = channels[who++];
            who %= channels.size();

            std::cout << "##################" << std::endl;
            std::cout << "send " << task << " to " << curr.Name() << "任务还剩：" << num << std::endl;
            std::cout << "##################" << std::endl;

            // c. 派发任务
            curr.Send(task);
            sleep(2);
        }
    }

    void CleanProcessPool()
    {
        // 关闭管道
        for (auto &c : channels)
        {
            c.Close();
        }

        // 回收子进程
        for (auto &c : channels)
        {
            pid_t rid = ::waitpid(c.Id(), nullptr, 0);
            if (rid > 0)
            {
                std::cout << "child " << rid << "wait ... success" << std::endl;
            }
        }
    }

    void DebugPrint()
    {
        for (auto &c : channels)
        {
            std::cout << c.Name() << std::endl;
        }
    }

private:
    std::vector<Channel> channels;
    int processnum;
    work_t work;
};
